package com.roamer.validator;

import com.roamer.util.CollectionUtils;
import com.roamer.util.StringUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Iterator;

/**
 * 枚举验证校验规则
 * <p>
 * 继承Constraint用于校验规则
 *
 * @author roamer
 * @version V1.0
 * @date 2019/8/26 9:43 下午
 */
public class EnumValueValidator implements ConstraintValidator<EnumValue, Object> {

    private Class<? extends Enum<?>> enumClass;
    private String enumMethod;

    /**
     * 初始化
     *
     * @param constraintAnnotation 注解对象
     */
    @Override
    public void initialize(EnumValue constraintAnnotation) {
        enumMethod = constraintAnnotation.enumMethod();
        enumClass = constraintAnnotation.enumClass();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
        if (value == null || enumClass == null || enumMethod == null) {
            return true;
        }

        Class<?> valueClass = value.getClass();
        boolean isCollection = false;
        if (Collection.class.isAssignableFrom(valueClass)) {
            if (CollectionUtils.isEmpty((Collection<?>) value)) {
                return true;
            }
            isCollection = true;
            for (Object o : ((Collection<?>) value)) {
                if (o != null) {
                    valueClass = o.getClass();
                    break;
                }
            }
        }
        try {
            Method method = enumClass.getMethod(enumMethod, valueClass);
            // 用于验证的函数返回类型否是 boolean 或者 Boolean
            if (!Boolean.TYPE.equals(method.getReturnType()) && !Boolean.class.equals(method.getReturnType())) {
                throw new RuntimeException(
                        StringUtils.formatIfArgs("%s method return is not boolean type in the %s class", enumMethod,
                                                 enumClass));
            }
            // 用于验证的函数是否是static修饰的
            if (!Modifier.isStatic(method.getModifiers())) {
                throw new RuntimeException(
                        StringUtils.formatIfArgs("%s method is not static method in the %s class", enumMethod,
                                                 enumClass));
            }
            if (isCollection) {
                // 执行验证
                Iterator iterator = ((Collection<?>) value).iterator();
                for (; iterator.hasNext() && (value = iterator.next()) != null; ) {
                    if (!(boolean) method.invoke(null, value)) {
                        return false;
                    }
                }
                return true;
            }

            return (boolean) method.invoke(null, value);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException | SecurityException e) {
            throw new RuntimeException(
                    StringUtils.formatIfArgs("This %s(%s) method does not exist in the %s", enumMethod, valueClass,
                                             enumClass), e);
        }
    }

}
